package club.babyf.lbs.service.amap;

import club.babyf.common.constants.ResultCode;
import club.babyf.common.exception.BusinessException;
import club.babyf.lbs.entity.amap.req.GeoCodeGeoParameterDto;
import club.babyf.lbs.entity.amap.req.WeatherInfoParameterDto;
import club.babyf.lbs.entity.amap.res.GeoCodeGeoDto;
import club.babyf.lbs.entity.amap.res.WeatherInfoDto;
import club.babyf.lbs.enums.LbsUriEnum;
import club.babyf.lbs.service.LbsService;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

/**
 * AMapLbsService.
 *
 * @author zhanglei.
 * @date 2025/1/10 15:35.
 * @description 高德基于位置服务.
 */
@Slf4j
public class AMapLbsService implements LbsService {

    private final AMapLbsProperties aMapLbsProperties;

    private final ObjectMapper objectMapper;

    public AMapLbsService(AMapLbsProperties aMapLbsProperties) {
        this.aMapLbsProperties = aMapLbsProperties;
        this.objectMapper = new ObjectMapper();
    }

    @Override
    public GeoCodeGeoDto geoCodeGeo(GeoCodeGeoParameterDto geoCodeGeoParameterDto) {
        // 获取接口地址和参数
        String urlWithParameter = getGeoCodeGeoUrl(geoCodeGeoParameterDto);
        // 发起请求
        return get(urlWithParameter, GeoCodeGeoDto.class);
    }

    @Override
    public WeatherInfoDto weatherInfo(WeatherInfoParameterDto weatherInfoParameterDto) {
        // 获取接口地址和参数
        String urlWithParameter = getWeatherInfoUrl(weatherInfoParameterDto);
        // 发起请求
        return get(urlWithParameter, WeatherInfoDto.class);
    }

    private <T> T get(String url, Class<T> clazz) {
        String body = HttpUtil.get(url);
        T t;
        try {
            t = objectMapper.readValue(body, clazz);
        } catch (JsonProcessingException e) {
            log.error("Data parsing exception, err reason: {}", e.getMessage());
            throw new BusinessException(ResultCode.Fail, "Data parsing exception");
        }
        return t;
    }

    private String getWeatherInfoUrl(WeatherInfoParameterDto weatherInfoParameterDto) {
        // 获取key
        String key = getKey(weatherInfoParameterDto.getKey());
        // 获取host
        String host = getHost();
        // 获取接口地址
        String url = host + LbsUriEnum.WEATHER_INFO.getUri();
        // 拼接参数
        url = url + "?key=" + key + "&city=" + getWeatherInfoCity(weatherInfoParameterDto);
        if (!strIsBlank(weatherInfoParameterDto.getExtensions())) {
            url = url + "?extensions=" + weatherInfoParameterDto.getExtensions();
        }
        if (!strIsBlank(weatherInfoParameterDto.getOutput())) {
            url = url + "?output=" + weatherInfoParameterDto.getOutput();
        }
        return url;
    }

    private String getGeoCodeGeoUrl(GeoCodeGeoParameterDto geoCodeGeoParameterDto) {
        // 获取key
        String key = getKey(geoCodeGeoParameterDto.getKey());
        // 获取host
        String host = getHost();
        // 获取接口地址
        String url = host + LbsUriEnum.GEO_CODE_GEO.getUri();
        // 拼接参数
        url = url + "?key=" + key + "&address=" + getGeoCodeGeoAddress(geoCodeGeoParameterDto);
        if (!strIsBlank(geoCodeGeoParameterDto.getCity())) {
            url = url + "?city=" + geoCodeGeoParameterDto.getCity();
        }
        if (!strIsBlank(geoCodeGeoParameterDto.getSig())) {
            url = url + "?sig=" + geoCodeGeoParameterDto.getSig();
        }
        if (!strIsBlank(geoCodeGeoParameterDto.getOutput())) {
            url = url + "?output=" + geoCodeGeoParameterDto.getOutput();
        }
        if (!strIsBlank(geoCodeGeoParameterDto.getCallback())) {
            url = url + "?callback=" + geoCodeGeoParameterDto.getCallback();
        }
        return url;
    }

    private String getWeatherInfoCity(WeatherInfoParameterDto weatherInfoParameterDto) {
        String city = weatherInfoParameterDto.getCity();
        if (strIsBlank(city)) {
            throw new BusinessException(ResultCode.Fail, "Please enter the city");
        }
        return city;
    }

    private String getGeoCodeGeoAddress(GeoCodeGeoParameterDto geoCodeGeoParameterDto) {
        String address = geoCodeGeoParameterDto.getAddress();
        if (strIsBlank(address)) {
            throw new BusinessException(ResultCode.Fail, "Please enter the address");
        }
        return address;
    }

    private String getHost() {
        String host = this.aMapLbsProperties.getHost();
        if (strIsBlank(host)) {
            throw new BusinessException(ResultCode.Fail, "Please configure the host");
        }
        return host;
    }

    private String getKey(String key) {
        if (strIsBlank(key)) {
            key = aMapLbsProperties.getKey();
        }
        if (strIsBlank(key)) {
            throw new BusinessException(ResultCode.Fail, "Please configure the key");
        }
        return key;
    }

    private boolean strIsBlank(String str) {
        return str == null || str.isBlank();
    }

}
